package com.wzz.seckillone.controller;

import com.alibaba.fastjson.JSON;
import com.wzz.seckillone.activeMq.MqSend;
import com.wzz.seckillone.common.AjaxResult;
import com.wzz.seckillone.common.Common;
import com.wzz.seckillone.pojo.*;
import com.wzz.seckillone.service.GoodsService;
import com.wzz.seckillone.service.SeckillGoodsService;
import com.wzz.seckillone.service.SeckillOrderService;
import com.wzz.seckillone.vo.GoodsVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;

/**
 * @ProjectName: seckillOne
 * @Package: com.wzz.seckillone.controller
 * @ClassName: SeckillController
 * @Author: wzz
 * @Description: 秒杀逻辑
 * @Date: 2022/3/16 1:28
 * @Version: 1.0
 */
@Controller()
@RequestMapping("/secKill")
@Slf4j
public class SecKillController implements InitializingBean {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SeckillGoodsService seckillGoodsService;
    @Autowired
    private Common common;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private SeckillOrderService seckillOrderService;
    @Autowired
    private MqSend mqSend;
    //k:goodsId v：true为无库存
    private HashMap<String,Boolean> emptyStock = new HashMap<>();



    /**
     * @Method
     * @Author wzz
     * @Version  1.0
     * @Description判断是否有库存 查询t_seckill_goods表中的库存
     *             一个user只允许买一个 根据goods——id和user_id查询是否有信息
     *
     *             用redis预减库存
     *             引入mq
     * @param
     * @Return
     * @Exception
     * @Date 2022/3/21 15:29
     */
    @PostMapping("/doSecKill")
    @ResponseBody
    public String doSecKill(String goodsId){
        AjaxResult result = new AjaxResult();
        try{
            User user = common.getUser();
            log.info("yonghu"+user);
            //是否重复抢购
            SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("order" + user.getUserId() + ":" + goodsId);
            Long decrement = redisTemplate.opsForValue().decrement("secKillGoods" + goodsId);
            if(seckillOrder != null){
                log.info("seckillOrder"+seckillOrder);
                result.setSuccess(false).setMessage("每个Id只能参加一个秒杀");
            }else if(emptyStock.get(goodsId)){
                //当无库存时 仍有大量的请求接入 频繁的redis查询浪费资源  定义一个标志位
                log.info("empty"+emptyStock.get(goodsId));
                result.setSuccess(false).setMessage("此秒杀商品已经卖完");
            }else if(decrement == 0){
                //用redis预减库存  decrement是原子性的  返回的是预减后的数
                emptyStock.put(goodsId,true);
                result.setSuccess(false).setMessage("此秒杀商品已经卖完");
            }else {
                //消息队列 doSecKill 实现流量削峰
                SecKillMessage killMessage = new SecKillMessage(user, goodsId);
                log.info("killMessage" + killMessage);
                mqSend.sendMsg(JSON.toJSONString(killMessage));
                result.setSuccess(true).setMessage("正在等待中");
            }
        }catch (Exception e){
            result.setSuccess(false).setMessage("下单出错");
        }
        return JSON.toJSONString(result);
    }



    /**
     * @Method
     * @Author wzz
     * @Version  1.0
     * @Description初始化系统加载的方法    把商品库存数量加载到redis中
     * @param
     * @Return
     * @Exception
     * @Date 2022/3/20 14:08
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> goodsVo = goodsService.findGoodsVo();
        if (goodsVo == null){
            return;
        }
        //把商品库存存入redis中  k:secKillGoods+goodsId  v:数量
        goodsVo.forEach((goods) ->{
            redisTemplate.opsForValue().set("secKillGoods"+goods.getId(),goods.getStockCount());
            //设置为有库存
            emptyStock.put(goods.getId(),false);
        });
    }
}
